package com.omp.markdown.controller;

import com.openhtmltopdf.pdfboxout.PdfRendererBuilder;
import com.openhtmltopdf.util.XRLog;
import com.vladsch.flexmark.html.HtmlRenderer;
import com.vladsch.flexmark.parser.Parser;
import com.vladsch.flexmark.util.data.MutableDataSet;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
import java.util.Base64;

/**
 * Markdown转PDF转换工具（兼容旧版API）
 *
 * @author yuan.tang
 * @since 2025/07/04
 */
public class MarkdownToPdf {

    static {
        // 禁用OpenHTMLToPDF的详细日志
        XRLog.setLoggingEnabled(false);
    }

    /**
     * 将Markdown文件转换为PDF
     *
     * @param mdFilePath    输入的Markdown文件路径
     * @param pdfOutputPath 输出的PDF文件路径（必须包含文件名）
     * @throws IOException 文件读写异常
     */
    public static void convertMarkdownToPdf(String mdFilePath, String pdfOutputPath) throws IOException {
        // 1. 读取Markdown文件内容（指定UTF-8编码）
        Path mdPath = Paths.get(mdFilePath);
        String markdownContent = new String(Files.readAllBytes(mdPath), StandardCharsets.UTF_8);
        // 获取Markdown文件所在目录，用于解析相对路径图片
        Path baseDir = mdPath.getParent();

        // 2. 将Markdown转换为HTML（确保UTF-8编码）
        String htmlContent = convertMarkdownToHtml(markdownContent);

        // 3. 处理HTML中的图片（支持本地和网络图片）
        String processedHtml = processImagesInHtml(htmlContent, baseDir);

        // 调试：输出处理后的HTML
        Files.write(Paths.get("debug.html"), processedHtml.getBytes(StandardCharsets.UTF_8));

        // 4. 将HTML转换为PDF（添加中文字体支持）
        generatePdfFromHtml(processedHtml, pdfOutputPath);
    }


    /**
     * 将Markdown内容转换为HTML（修复换行问题）
     *
     * @param markdown Markdown格式文本
     * @return 转换后的HTML内容
     */
    private static String convertMarkdownToHtml(String markdown) {
        // 配置Markdown解析选项
        MutableDataSet options = new MutableDataSet();

        // 关键修复：启用硬换行（将单个换行符转换为<br>）
        options.set(HtmlRenderer.SOFT_BREAK, "<br />");

        // 创建Markdown解析器
        Parser parser = Parser.builder(options).build();
        // 创建HTML渲染器
        HtmlRenderer renderer = HtmlRenderer.builder(options).build();
        // 解析并渲染Markdown为HTML
        return renderer.render(parser.parse(markdown));
    }

    /**
     * 处理HTML中的图片标签（支持本地和网络图片）
     *
     * @param html    HTML内容
     * @param baseDir 图片基础路径（Markdown文件所在目录）
     * @return 处理后的HTML内容
     */
    private static String processImagesInHtml(String html, Path baseDir) {
        // 使用Jsoup解析HTML（指定UTF-8编码）
        Document doc = Jsoup.parse(html, "UTF-8");
        // 选择所有图片标签
        Elements imgTags = doc.select("img");

        // 遍历处理每个图片标签
        for (Element img : imgTags) {
            // 获取图片src属性
            String src = img.attr("src");
            // 跳过空路径
            if (src == null || src.isEmpty()) {
                continue;
            }

            try {
                // 判断是网络图片还是本地图片
                if (isNetworkImage(src)) {
                    // 处理网络图片（使用安全的下载方法）
                    String base64Image = downloadNetworkImageToBase64(src);
                    img.attr("src", base64Image);
                } else {
                    // 处理本地图片
                    Path imgPath = resolveImagePath(src, baseDir);
                    if (Files.exists(imgPath)) {
                        String base64Image = convertLocalImageToBase64(imgPath);
                        img.attr("src", base64Image);
                    } else {
                        System.err.println("本地图片不存在: " + imgPath);
                    }
                }
            } catch (Exception e) {
                System.err.println("处理图片失败: " + src);
                e.printStackTrace();
            }
        }

        // 修复：使用XML输出模式确保自闭合标签正确处理
        doc.outputSettings().syntax(Document.OutputSettings.Syntax.xml);
        // 返回处理后的HTML
        return doc.outerHtml();
    }


    /**
     * 判断是否为网络图片
     *
     * @param src 图片路径
     * @return true如果是网络图片，false如果是本地图片
     */
    private static boolean isNetworkImage(String src) {
        return src.startsWith("http://") || src.startsWith("https://");
    }

    /**
     * 解析图片绝对路径
     *
     * @param src     图片路径（相对/绝对）
     * @param baseDir 基础目录（用于解析相对路径）
     * @return 图片绝对路径
     */
    private static Path resolveImagePath(String src, Path baseDir) {
        Path path = Paths.get(src);
        // 如果是绝对路径直接返回，否则拼接基础目录
        return path.isAbsolute() ? path : baseDir.resolve(src).normalize();
    }

    /**
     * 将本地图片转换为Base64编码
     *
     * @param imagePath 图片文件路径
     * @return Base64编码的图片数据
     * @throws IOException 文件读取异常
     */
    private static String convertLocalImageToBase64(Path imagePath) throws IOException {
        // 读取图片字节
        byte[] imageBytes = Files.readAllBytes(imagePath);
        // 获取图片MIME类型
        String mimeType = getImageMimeType(imagePath);
        // 构建Base64数据URI
        return "data:" + mimeType + ";base64," + Base64.getEncoder().encodeToString(imageBytes);
    }

    /**
     * 下载网络图片并转换为Base64编码
     *
     * @param imageUrl 图片URL
     * @return Base64编码的图片数据
     * @throws IOException 网络或IO异常
     */
    private static String downloadNetworkImageToBase64(String imageUrl) throws IOException {
        // 创建URL对象
        URL url = new URL(imageUrl);

        // 打开HTTP/HTTPS连接
        HttpURLConnection connection;
        if (url.getProtocol().equalsIgnoreCase("https")) {
            // 创建信任所有证书的HTTPS连接
            connection = createTrustAllHttpsConnection(url);
        } else {
            // 创建HTTP连接
            connection = (HttpURLConnection) url.openConnection();
        }

        // 设置连接参数
        connection.setRequestMethod("GET");
        connection.setConnectTimeout(10000); // 10秒连接超时
        connection.setReadTimeout(30000);    // 30秒读取超时
        connection.setRequestProperty("User-Agent", "Mozilla/5.0"); // 模拟浏览器

        // 检查响应状态
        int responseCode = connection.getResponseCode();
        if (responseCode != HttpURLConnection.HTTP_OK) {
            throw new IOException("图片下载失败: HTTP " + responseCode + " - " + imageUrl);
        }

        // 获取MIME类型
        String contentType = connection.getContentType();
        String mimeType = (contentType != null && contentType.startsWith("image/"))
                ? contentType.split(";")[0] // 移除可能附加的字符集信息
                : "image/jpeg"; // 默认类型

        // 读取图片数据
        try (InputStream inputStream = connection.getInputStream();
             ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {

            // 使用缓冲区读取提高性能
            byte[] buffer = new byte[8192];
            int bytesRead;
            while ((bytesRead = inputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, bytesRead);
            }

            byte[] imageBytes = outputStream.toByteArray();
            // 将图片转换为Base64编码
            return "data:" + mimeType + ";base64," + Base64.getEncoder().encodeToString(imageBytes);
        } finally {
            connection.disconnect();
        }
    }


    /**
     * 创建信任所有证书的HTTPS连接
     *
     * @param url 图片URL
     * @return HTTPS连接对象
     * @throws IOException 如果创建连接失败
     */
    private static HttpsURLConnection createTrustAllHttpsConnection(URL url) throws IOException {
        try {
            // 创建信任所有证书的SSL上下文
            SSLContext sslContext = SSLContext.getInstance("TLS");
            sslContext.init(null, new TrustManager[] {
                    new X509TrustManager() {
                        @Override
                        public X509Certificate[] getAcceptedIssuers() { return null; }
                        @Override
                        public void checkClientTrusted(X509Certificate[] certs, String authType) {}
                        @Override
                        public void checkServerTrusted(X509Certificate[] certs, String authType) {}
                    }
            }, new SecureRandom());

            // 创建HTTPS连接
            HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
            connection.setSSLSocketFactory(sslContext.getSocketFactory());
            // 信任所有主机名
            connection.setHostnameVerifier((hostname, session) -> true);

            return connection;
        } catch (Exception e) {
            throw new IOException("创建安全连接失败: " + e.getMessage(), e);
        }
    }

    /**
     * 获取图片的MIME类型
     *
     * @param imagePath 图片路径
     * @return MIME类型字符串
     */
    private static String getImageMimeType(Path imagePath) throws IOException {
        // 尝试通过文件系统探测MIME类型
        String mimeType = Files.probeContentType(imagePath);

        // 如果无法探测，根据文件扩展名判断
        if (mimeType == null) {
            String fileName = imagePath.getFileName().toString().toLowerCase();
            if (fileName.endsWith(".jpg") || fileName.endsWith(".jpeg")) {
                mimeType = "image/jpeg";
            } else if (fileName.endsWith(".png")) {
                mimeType = "image/png";
            } else if (fileName.endsWith(".gif")) {
                mimeType = "image/gif";
            } else if (fileName.endsWith(".svg")) {
                mimeType = "image/svg+xml";
            } else if (fileName.endsWith(".bmp")) {
                mimeType = "image/bmp";
            } else if (fileName.endsWith(".webp")) {
                mimeType = "image/webp";
            } else {
                throw new IOException("不支持的图片格式: " + fileName);
            }
        }
        return mimeType;
    }

    /**
     * 将HTML内容渲染为PDF文件（兼容旧版API）
     *
     * @param html       HTML内容
     * @param outputPath 输出PDF文件路径
     * @throws IOException 文件写入异常
     */
    private static void generatePdfFromHtml(String html, String outputPath) throws IOException {
        // 创建完整的HTML结构（包含完整CSS样式）
        // 修改后的CSS - 关键调整图片对齐方式和文字环绕
        String fullHtml = "<!DOCTYPE html>\n" +
                "<html>\n" +
                "<head>\n" +
                "    <meta charset=\"UTF-8\" />\n" +
                "    <style>\n" +
                "        /* 页面尺寸和边距 */\n" +
                "        @page {\n" +
                "            size: A4;\n" +
                "            margin: 2cm;\n" +
                "        }\n" +
                "        \n" +
                "        body {\n" +
                "            margin: 0;\n" +
                "            padding: 20px;\n" +
                "        }\n" +
                "        \n" +
                "        /* 关键修复：代码块使用中文字体 */\n" +
                "        pre, code {\n" +
                "            font-family: 'SimSun', monospace !important; /* 强制使用中文字体 */\n" +
                "        }\n" +
                "        \n" +
                "        /* 图片左对齐样式 */\n" +
                "        p, pre, table, ul, ol, blockquote {\n" +
                "            clear: both;\n" +
                "        }\n" +
                "        \n" +
                "        img {\n" +
                "            float: none !important;\n" +
                "            clear: both;\n" +
                "            display: block;\n" +
                "            margin: 12px 0;\n" +
                "            margin-right: auto;\n" +
                "            max-width: 100%;\n" +
                "            height: auto;\n" +
                "        }\n" +
                "        \n" +
                "        /* 基础样式重置 */\n" +
                "        * { box-sizing: border-box; }\n" +
                "        \n" +
                "        body {\n" +
                "            font-family: 'SimSun', sans-serif;\n" +
                "            font-size: 12pt;\n" +
                "            line-height: 1.6;\n" +
                "            color: #000;\n" +
                "        }\n" +
                "        \n" +
                "        /* 段落样式 */\n" +
                "        p {\n" +
                "            margin: 0 0 12px 0;\n" +
                "            text-align: justify;\n" +
                "        }\n" +
                "        \n" +
                "        /* 标题样式 */\n" +
                "        h1, h2, h3, h4, h5, h6 {\n" +
                "            margin: 24px 0 12px 0;\n" +
                "            font-weight: bold;\n" +
                "            page-break-after: avoid;\n" +
                "        }\n" +
                "        \n" +
                "        h1 { font-size: 18pt; }\n" +
                "        h2 { font-size: 16pt; }\n" +
                "        h3 { font-size: 14pt; }\n" +
                "        h4 { font-size: 12pt; }\n" +
                "        \n" +
                "        /* 列表样式 */\n" +
                "        ul, ol {\n" +
                "            margin: 12px 0;\n" +
                "            padding-left: 30px;\n" +
                "        }\n" +
                "        \n" +
                "        li {\n" +
                "            margin-bottom: 6px;\n" +
                "        }\n" +
                "        \n" +
                "        /* 代码块样式 */\n" +
                "        pre {\n" +
                "            background-color: #f5f5f5;\n" +
                "            border: 1px solid #ddd;\n" +
                "            border-radius: 3px;\n" +
                "            padding: 10px;\n" +
                "            overflow: auto;\n" +
                "            margin: 12px 0;\n" +
                "            font-size: 10pt;\n" + // 字体族已在上方统一设置
                "            line-height: 1.4;\n" +
                "        }\n" +
                "        \n" +
                "        code {\n" +
                "            background-color: #f5f5f5;\n" +
                "            padding: 2px 4px;\n" +
                "            border-radius: 3px;\n" +
                "            font-size: 10pt;\n" + // 字体族已在上方统一设置
                "        }\n" +
                "        \n" +
                "        /* 表格样式 */\n" +
                "        table {\n" +
                "            width: 100%;\n" +
                "            border-collapse: collapse;\n" +
                "            margin: 12px 0;\n" +
                "            font-size: 10pt;\n" +
                "        }\n" +
                "        \n" +
                "        th, td {\n" +
                "            border: 1px solid #ddd;\n" +
                "            padding: 6px 8px;\n" +
                "            text-align: left;\n" +
                "        }\n" +
                "        \n" +
                "        th {\n" +
                "            background-color: #f0f0f0;\n" +
                "            font-weight: bold;\n" +
                "        }\n" +
                "        \n" +
                "        /* 打印优化 */\n" +
                "        @media print {\n" +
                "            body {\n" +
                "                padding: 0;\n" +
                "            }\n" +
                "            \n" +
                "            pre, blockquote, table {\n" +
                "                page-break-inside: avoid;\n" +
                "            }\n" +
                "            \n" +
                "            h1, h2, h3, h4, h5, h6 {\n" +
                "                page-break-after: avoid;\n" +
                "            }\n" +
                "            \n" +
                "            img {\n" +
                "                max-width: 95%;\n" +
                "            }\n" +
                "        }\n" +
                "    </style>\n" +
                "</head>\n" +
                "<body>\n" +
                html + "\n" +
                "</body>\n" +
                "</html>";
        // 创建输出流
        try (OutputStream os = new FileOutputStream(outputPath)) {
            // 配置PDF渲染器
            PdfRendererBuilder builder = new PdfRendererBuilder();
            // 使用快速渲染模式
            builder.useFastMode();

            // 明确注册中文字体
            registerChineseFont(builder);

            // 添加中文字体支持
            Path fontPath = Paths.get("C:/Windows/Fonts/simsun.ttc");

            // Linux/Mac备用路径
            if (!Files.exists(fontPath)) {
                fontPath = Paths.get("/usr/share/fonts/truetype/droid/DroidSansFallbackFull.ttf");
            }

            if (Files.exists(fontPath)) {
                builder.useFont(fontPath.toFile(), "SimSun");
            } else {
                System.err.println("警告：未找到中文字体文件，中文可能显示异常");
                // 尝试使用内置字体
                try {
                    builder.useFont(new File("src/main/resources/fonts/simsun.ttc"), "SimSun");
                } catch (Exception e) {
                    System.err.println("内置字体也不存在，PDF中文将无法显示");
                }
            }

            // 使用兼容方法设置页面尺寸
            builder.useDefaultPageSize(210, 297, PdfRendererBuilder.PageSizeUnits.MM); // A4尺寸

            // 设置HTML内容
            builder.withHtmlContent(fullHtml, null);
            // 设置输出流
            builder.toStream(os);
            // 执行渲染
            builder.run();
        }
    }

    // 专门的中文字体注册方法
    private static void registerChineseFont(PdfRendererBuilder builder) throws IOException {
        // 尝试多个可能的字体路径
        String[] fontPaths = {
                "C:/Windows/Fonts/simsun.ttc",                 // Windows
                "/usr/share/fonts/truetype/droid/DroidSansFallbackFull.ttf", // Linux
                "/System/Library/Fonts/PingFang.ttc",           // macOS
                "/Library/Fonts/Arial Unicode.ttf",             // macOS
                "src/main/resources/fonts/simsun.ttc"           // 项目内嵌字体
        };

        boolean fontRegistered = false;

        for (String path : fontPaths) {
            File fontFile = new File(path);
            if (fontFile.exists()) {
                try {
                    // 注册字体并命名为"SimSun"
                    builder.useFont(fontFile, "SimSun");
                    System.out.println("成功加载字体: " + path);
                    fontRegistered = true;
                    break;
                } catch (Exception e) {
                    System.err.println("字体加载失败: " + path);
                    e.printStackTrace();
                }
            }
        }

        if (!fontRegistered) {
            System.err.println("警告：未找到任何中文字体文件，中文显示可能异常");
        }
    }

    public static void main(String[] args) {


        try {
            // 使用命令行参数调用转换方法
//            convertMarkdownToPdf("D:\\document\\study\\项目实战收获\\部署踩坑\\文档知识库部署.md", "C:\\Users\\唐远\\Desktop\\文档知识库1.pdf");
            convertMarkdownToPdf("C:\\Users\\唐远\\Desktop\\（七）大模型训推.md", "C:\\Users\\唐远\\Desktop\\（七）大模型训推11.pdf");
            System.out.println("PDF生成成功: " );
        } catch (Exception e) {
            System.err.println("转换失败:");
            e.printStackTrace();
        }
    }
}